package org.ehe.system.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.ehe.common.core.constant.RoleKeyConstants;
import org.ehe.common.core.exception.ServiceException;
import org.ehe.common.core.service.RoleService;
import org.ehe.common.core.utils.DateUtils;
import org.ehe.common.mybatis.core.page.PageQuery;
import org.ehe.common.mybatis.core.page.TableDataInfo;
import org.ehe.common.satoken.utils.LoginHelper;
import org.ehe.system.domain.HrEmployee;
import org.ehe.system.domain.bo.HrEmployeeBo;
import org.ehe.system.domain.bo.SysUserBo;
import org.ehe.system.domain.vo.*;
import org.ehe.system.mapper.HrEmployeeMapper;
import org.ehe.system.service.*;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 员工主信息Service业务层处理
 *
 * @author zhangnn
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class HrEmployeeServiceImpl implements IHrEmployeeService {

    private final HrEmployeeMapper baseMapper;
    private final Converter converter;
    private final ISysUserService userService;
    private final IHrEmployeeFamilyService familyService;
    private final IHrEmployeeAttachmentService attachmentService;

    // 身份证号正则表达式（18位，最后一位可以是数字或X）
    private static final Pattern IDCARD_PATTERN = Pattern
            .compile("^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$");

    /**
     * 查询员工主信息
     */
    @Override
    public HrEmployeeVo queryById(Long employeeId) {
        HrEmployeeVo hrEmployeeVo = baseMapper.selectVoById(employeeId);
        if (Objects.nonNull(hrEmployeeVo)) {
            List<HrEmployeeFamilyVo> hrEmployeeFamilyVos = familyService
                    .queryListByEmployeeNo(hrEmployeeVo.getEmployeeNo());
            List<HrEmployeeAttachmentVo> hrEmployeeAttachmentVos = attachmentService
                    .queryListByEmployeeNo(hrEmployeeVo.getEmployeeNo());

            hrEmployeeVo.setFamilyVos(hrEmployeeFamilyVos);
            hrEmployeeVo.setAttachmentVos(hrEmployeeAttachmentVos);

            Long userId = hrEmployeeVo.getUserId();
            SysUserVo sysUserVo = userService.selectUserById(userId);
            if (Objects.nonNull(sysUserVo)) {
                hrEmployeeVo.setRoleVos(sysUserVo.getRoles());
                hrEmployeeVo.setPostVos(sysUserVo.getPosts());
            }
        }

        return hrEmployeeVo;
    }

    /**
     * 根据工号查询员工信息
     */
    @Override
    public HrEmployeeVo queryByEmployeeNo(String employeeNo) {
        HrEmployeeVo hrEmployeeVo = baseMapper.selectVoOne(new LambdaQueryWrapper<HrEmployee>()
            .eq(HrEmployee::getEmployeeNo, employeeNo));
        Long userId = hrEmployeeVo.getUserId();
        SysUserVo sysUserVo = userService.selectUserById(userId);
        if (Objects.nonNull(sysUserVo)) {
            hrEmployeeVo.setRoleVos(sysUserVo.getRoles());
            hrEmployeeVo.setPostVos(sysUserVo.getPosts());
        }
        return hrEmployeeVo;
    }

    /**
     * 查询员工主信息列表
     */
    @Override
    public TableDataInfo<HrEmployeeVo> queryPageList(HrEmployeeBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<HrEmployee> lqw = buildQueryWrapper(bo);
        Page<HrEmployeeVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        result.getRecords().forEach(e -> {
            Long userId = e.getUserId();
            SysUserVo sysUserVo = userService.selectUserById(userId);
            if (Objects.nonNull(sysUserVo)) {
                e.setRoleVos(sysUserVo.getRoles());
                e.setPostVos(sysUserVo.getPosts());
            }
        });
        return TableDataInfo.build(result);
    }

    /**
     * 查询员工主信息列表
     */
    @Override
    public List<HrEmployeeVo> queryList(HrEmployeeBo bo) {
        LambdaQueryWrapper<HrEmployee> lqw = buildQueryWrapper(bo);
        List<HrEmployeeVo> hrEmployeeVos = baseMapper.selectVoList(lqw);
        hrEmployeeVos.forEach(e -> {
            Long userId = e.getUserId();
            SysUserVo sysUserVo = userService.selectUserById(userId);
            if (Objects.nonNull(sysUserVo)) {
                e.setRoleVos(sysUserVo.getRoles());
                e.setPostVos(sysUserVo.getPosts());
            }
        });
        return hrEmployeeVos;
    }

    private LambdaQueryWrapper<HrEmployee> buildQueryWrapper(HrEmployeeBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<HrEmployee> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getEmployeeNo()), HrEmployee::getEmployeeNo, bo.getEmployeeNo());
        lqw.like(StringUtils.isNotBlank(bo.getEmployeeName()), HrEmployee::getEmployeeName, bo.getEmployeeName());
        lqw.eq(ObjectUtil.isNotNull(bo.getDeptId()), HrEmployee::getDeptId, bo.getDeptId());
        // lqw.eq(ObjectUtil.isNotNull(bo.getPostId()), HrEmployee::getPostId,
        // bo.getPostId());
        lqw.eq(StringUtils.isNotBlank(bo.getContractType()), HrEmployee::getContractType, bo.getContractType());
        lqw.eq(StringUtils.isNotBlank(bo.getEmployeeStatus()), HrEmployee::getEmployeeStatus, bo.getEmployeeStatus());
        lqw.eq(StringUtils.isNotBlank(bo.getSalaryLevel()), HrEmployee::getSalaryLevel, bo.getSalaryLevel());
        lqw.eq(StringUtils.isNotBlank(bo.getEducation()), HrEmployee::getEducation, bo.getEducation());
        lqw.between(params.get("beginEntryDate") != null && params.get("endEntryDate") != null,
                HrEmployee::getEntryDate, params.get("beginEntryDate"), params.get("endEntryDate"));
        lqw.orderByDesc(HrEmployee::getCreateTime);
        return lqw;
    }

    /**
     * 新增员工主信息
     */
    @Override
    public Boolean insertByBo(HrEmployeeBo bo) {
        // 校验身份证号合法性
        if (StringUtils.isNotBlank(bo.getIdCard())) {
            if (!isValidIdCard(bo.getIdCard())) {
                throw new ServiceException("身份证号格式不正确");
            }
            // 校验身份证号唯一性
            if (!checkIdCardUnique(bo.getIdCard(), null)) {
                throw new ServiceException("身份证号已存在");
            }
        }

        // 1. 自动生成4位数字工号
        if (StringUtils.isBlank(bo.getEmployeeNo())) {
            String employeeNo = generateEmployeeCode();
            bo.setEmployeeNo(employeeNo);
        }
        // 2. 通过身份证号获取性别（0男、1女、2未知）
        String idCard = bo.getIdCard();
        if (StringUtils.isNotBlank(idCard)) {
            Integer sex = getSexFromIdCard(idCard);
            bo.setSex(String.valueOf(sex));
        }
        HrEmployee add = converter.convert(bo, HrEmployee.class);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setEmployeeId(add.getEmployeeId());
        }

        // 将信息加入到sys_user表
        SysUserBo user = new SysUserBo();
        user.setUserName(bo.getMobile());
        user.setNickName(bo.getEmployeeName());

        System.out.println("截取的手机号后六位=====>>>>" + bo.getMobile().substring(5, 11));
        // 设定密码
        user.setPassword(BCrypt.hashpw(bo.getMobile().substring(5, 11)));
        user.setDeptId(bo.getDeptId());
        user.setPhonenumber(bo.getMobile());
        user.setSex(bo.getSex());
        user.setEmployeeId(bo.getEmployeeId());
        user.setRoleIds(bo.getRoleIds());
        user.setPostIds(bo.getPostIds());
        userService.insertUser(user);
        log.info("员工新增到sys_user表成功，员工employee_id={}", bo.getEmployeeId());

        // 更新用户ID
        add.setUserId(user.getUserId());
        this.baseMapper.updateById(add);
        log.info("员工新增--->更新用户ID={}", bo.getEmployeeId());
        return flag;
    }

    /**
     * 修改员工主信息
     */
    @Override
    public Boolean updateByBo(HrEmployeeBo bo) {
        // 校验工号唯一性
        if (!checkEmployeeNoUnique(bo.getEmployeeNo(), bo.getEmployeeId())) {
            throw new ServiceException("工号已存在");
        }

        // 校验身份证号合法性
        if (StringUtils.isNotBlank(bo.getIdCard())) {
            if (!isValidIdCard(bo.getIdCard())) {
                throw new ServiceException("身份证号格式不正确");
            }
            // 校验身份证号唯一性（排除自己）
            if (!checkIdCardUnique(bo.getIdCard(), bo.getEmployeeId())) {
                throw new ServiceException("身份证号已存在");
            }
        }
        // HR\ADMIN
        if (StpUtil.hasRoleOr(RoleKeyConstants.HR_ROLES.toArray(new String[0]))) {
            HrEmployee update = converter.convert(bo, HrEmployee.class);
            boolean result = baseMapper.updateById(update) > 0;

            // 同步更新sys_user表中的信息
            if (result && update.getUserId() != null) {
                syncUserInformation(update, bo);
            }
            return result;
        }
        // 判断是否员工本人
        SysUserVo sysUserVo = userService.selectUserById(LoginHelper.getUserId());
        // 获取角色
        List<SysRoleVo> roles = sysUserVo.getRoles();
        boolean roleHrAdmin = false;
        for (SysRoleVo role : roles) {
            // 行政专业
            roleHrAdmin = role.getRoleKey().equals("roleAdmin");
            if (roleHrAdmin) {
                HrEmployee update = converter.convert(bo, HrEmployee.class);
                boolean result = baseMapper.updateById(update) > 0;

                // 同步更新sys_user表中的信息
                if (result && update.getUserId() != null) {
                    syncUserInformation(update, bo);
                }

                return result;
            }
        }
        // 同一个人的时候
        if (sysUserVo.getEmployeeId() == bo.getEmployeeId()) {
            // 判断是否是敏感信息
            HrEmployee existEmp = this.baseMapper.selectById(bo.getEmployeeId());
            // 身份证号不一样
            if (!existEmp.getIdCard().equals(bo.getIdCard()) ||
                    !existEmp.getMobile().equals(bo.getMobile()) ||
                    !existEmp.getEmployeeName().equals(bo.getEmployeeName())) {
                // 触发审批

                return true;
            }
        }
        HrEmployee update = converter.convert(bo, HrEmployee.class);
        boolean result = baseMapper.updateById(update) > 0;

        // 同步更新sys_user表中的信息
        if (result && update.getUserId() != null) {
            syncUserInformation(update, bo);
        }

        return result;
    }

    /**
     * 同步更新sys_user表中的信息
     *
     * @param employee 员工实体
     * @param bo       员工业务对象
     */
    private void syncUserInformation(HrEmployee employee, HrEmployeeBo bo) {
        try {
            // 查询现有的用户信息
            SysUserVo existingUser = userService.selectUserById(employee.getUserId());
            if (existingUser != null) {
                // 构造更新用户信息的业务对象
                SysUserBo userBo = new SysUserBo();
                userBo.setUserId(employee.getUserId());
                userBo.setUserName(bo.getMobile());
                userBo.setNickName(bo.getEmployeeName());
                userBo.setDeptId(bo.getDeptId());
                userBo.setPhonenumber(bo.getMobile());
                userBo.setSex(bo.getSex());
                userBo.setEmployeeId(bo.getEmployeeId());
                userBo.setRoleIds(bo.getRoleIds());
                userBo.setPostIds(bo.getPostIds());

                // 更新用户信息
                userService.updateUser(userBo);
                log.info("同步更新sys_user表成功，用户ID={}", employee.getUserId());
            }
        } catch (Exception e) {
            log.error("同步更新sys_user表失败，用户ID={}", employee.getUserId(), e);
        }
    }

    /**
     * 校验工号是否唯一
     */
    @Override
    public Boolean checkEmployeeNoUnique(String employeeNo, Long employeeId) {
        boolean exists = baseMapper.exists(new LambdaQueryWrapper<HrEmployee>()
                .eq(HrEmployee::getEmployeeNo, employeeNo)
                .ne(ObjectUtil.isNotNull(employeeId), HrEmployee::getEmployeeId, employeeId));
        return !exists;
    }

    /**
     * 校验身份证号是否唯一
     */
    public Boolean checkIdCardUnique(String idCard, Long employeeId) {
        boolean exists = baseMapper.exists(new LambdaQueryWrapper<HrEmployee>()
                .eq(HrEmployee::getIdCard, idCard)
                .ne(ObjectUtil.isNotNull(employeeId), HrEmployee::getEmployeeId, employeeId));
        return !exists;
    }

    /**
     * 批量删除员工主信息
     */
    @Override
    public Boolean deleteByIds(Collection<Long> employeeIds) {
        return baseMapper.deleteByIds(employeeIds) > 0;
    }

    /**
     * 员工离职
     */
    @Override
    public Boolean employeeLeave(Long employeeId, String leaveDate, String leaveReason) {
        HrEmployee employee = baseMapper.selectById(employeeId);
        if (ObjectUtil.isNull(employee)) {
            throw new ServiceException("员工不存在");
        }

        if ("3".equals(employee.getEmployeeStatus())) {
            throw new ServiceException("员工已离职");
        }

        employee.setEmployeeStatus("3");
        employee.setLeaveDate(DateUtils.parseDate(leaveDate));
        employee.setLeaveReason(leaveReason);
        return baseMapper.updateById(employee) > 0;
    }

    /**
     * 生成4位数字工号（0001、0002...）
     * 逻辑：查询当前最大工号，加1后补0至3位
     */
    public String generateEmployeeCode() {
        // 查询数据库中最大的工号
        HrEmployee maxEmployee = this.baseMapper.selectOne(new LambdaQueryWrapper<HrEmployee>()
                .select(HrEmployee::getEmployeeNo)
                .orderByDesc(HrEmployee::getEmployeeNo)
                .last("limit 1"));

        String maxNo = (maxEmployee != null) ? maxEmployee.getEmployeeNo() : null;
        if (maxNo == null || maxNo.isEmpty()) {
            // 若没有工号，从0001开始
            return "0001";
        }

        // 转换为数字并加1（处理纯数字工号）
        try {
            int num = Integer.parseInt(maxNo);
            num++;
            // 格式化为4位数字，不足补0
            return String.format("%04d", num);
        } catch (NumberFormatException e) {
            // 若工号格式异常，默认从0001开始
            log.error("工号格式异常，maxNo={}", maxNo, e);
            return "0001";
        }
    }

    /**
     * 根据身份证号获取性别（0男、1女、2未知）
     *
     * @param idCard 18位身份证号（若为null或格式错误，返回2未知）
     */
    private Integer getSexFromIdCard(String idCard) {
        // 校验身份证号合法性
        if (idCard == null || idCard.length() != 18) {
            return 2; // 未知
        }

        try {
            // 获取第17位字符（索引16）
            char genderChar = idCard.charAt(16);
            int genderNum = Character.getNumericValue(genderChar);

            // 奇数→男（0），偶数→女（1）
            return genderNum % 2 == 1 ? 0 : 1;
        } catch (Exception e) {
            // 异常情况（如字符非数字）返回未知
            log.error("解析身份证号性别失败，idCard={}", idCard, e);
            return 2;
        }
    }

    /**
     * 校验身份证号合法性
     *
     * @param idCard 身份证号
     * @return 是否合法
     */
    private boolean isValidIdCard(String idCard) {
        // 基本格式校验
        if (idCard == null || !IDCARD_PATTERN.matcher(idCard).matches()) {
            return false;
        }

        // 校验地区码（前6位）
        String areaCode = idCard.substring(0, 6);
        if (!isValidAreaCode(areaCode)) {
            return false;
        }

        // 校验出生日期（第7-14位）
        String birthDate = idCard.substring(6, 14);
        if (!isValidBirthDate(birthDate)) {
            return false;
        }

        // 校验校验码（第18位）
        return isValidCheckCode(idCard);
    }

    /**
     * 校验地区码是否有效
     *
     * @param areaCode 地区码
     * @return 是否有效
     */
    private boolean isValidAreaCode(String areaCode) {
        // 这里简化处理，实际应该有完整的地区码校验逻辑
        // 可以维护一个有效的地区码列表进行校验
        return areaCode != null && areaCode.length() == 6 && areaCode.matches("\\d{6}");
    }

    /**
     * 校验出生日期是否有效
     *
     * @param birthDate 出生日期（格式：yyyyMMdd）
     * @return 是否有效
     */
    private boolean isValidBirthDate(String birthDate) {
        try {
            int year = Integer.parseInt(birthDate.substring(0, 4));
            int month = Integer.parseInt(birthDate.substring(4, 6));
            int day = Integer.parseInt(birthDate.substring(6, 8));

            // 简单的日期有效性校验
            if (year < 1900 || year > 2025)
                return false;
            if (month < 1 || month > 12)
                return false;
            if (day < 1 || day > 31)
                return false;

            // 更精确的日期校验可以使用LocalDate等工具类
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 校验身份证号的校验码是否正确
     *
     * @param idCard 18位身份证号
     * @return 校验码是否正确
     */
    private boolean isValidCheckCode(String idCard) {
        // 加权因子
        int[] weight = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };
        // 校验码对应值
        char[] checkCode = { '1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2' };

        int sum = 0;
        for (int i = 0; i < 17; i++) {
            sum += (idCard.charAt(i) - '0') * weight[i];
        }

        int mod = sum % 11;
        char checkBit = checkCode[mod];
        return checkBit == idCard.charAt(17);
    }

    /**
     * 根据用户ID获取员工信息
     *
     * @param userId
     * @return
     */
    @Override
    public HrEmployee queryByUserId(Long userId) {
        return this.baseMapper.selectOne(new LambdaQueryWrapper<HrEmployee>()
                .eq(HrEmployee::getUserId, userId).last("limit 1"));
    }

    @Override
    public List<HrEmployee> getUserIdByEmployeeNos(List<String> employeeNos) {
        return this.baseMapper
                .selectList(new LambdaQueryWrapper<HrEmployee>().in(HrEmployee::getEmployeeNo, employeeNos));
    }

    @Override
    public List<String> queryByEmployeeName(String employeeName) {
        return this.baseMapper.selectList(new LambdaQueryWrapper<HrEmployee>()
                .like(HrEmployee::getEmployeeName, employeeName))
                .stream()
                .map(HrEmployee::getEmployeeNo)
                .collect(Collectors.toList());
    }

}
